﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using NAnt.Core;
using NAnt.SVN.Util;
using NAnt.SVN.Tasks;

namespace NAnt.SVN.Process
{
    /// <summary>
    /// Helper class to run a process.
    /// $Id$
    /// </summary>
    internal class ProcessRunner : AbstractProcessRunner
    {
        #region Private Fields

        private string  basedirectory;
        private bool hasrun = false;
        private int exitcode = -1;
        private string output = "";
        private string rawoutput = "";
        private System.Diagnostics.Process process;

        #endregion

        #region Public fields

        /// <summary>
        /// Name of the executable, SVN must be installed on the computer
        /// </summary>
        public static string EXECUTABLE = "svn";

        /// <summary>
        /// Base execution directory
        /// </summary>
        public string BaseDirectory
        {
            get 
            {
                return basedirectory;
            }
        }

        #endregion

        #region Event methods

        /// <summary>
        /// This delegate is called
        /// </summary>
        /// <param name="e"></param>
        public delegate void OnHasRunEventHandler(ProcessRunnerData e);

        /// <summary>
        /// This ivent is called after a process has run
        /// </summary>
        public event OnHasRunEventHandler OnHasRun;

        #endregion

        #region Run methods

        /// <summary>
        /// Create the process
        /// </summary>
        /// <returns></returns>
        private System.Diagnostics.Process createProcess(ProcessRunnerArguments e)
        {
            System.Diagnostics.Process p = new System.Diagnostics.Process();
            //Configure command
            p.StartInfo.WorkingDirectory = e.Task.Project.BaseDirectory;
            p.StartInfo.FileName = EXECUTABLE;
            p.StartInfo.Arguments = e.Command + " " + e.Options;
            p.StartInfo.UseShellExecute = false;
            p.StartInfo.CreateNoWindow = true;
            p.StartInfo.RedirectStandardOutput = true;
            p.StartInfo.RedirectStandardError = true;
            //Configure output
            p.OutputDataReceived += new DataReceivedEventHandler(DataReceived);
            p.ErrorDataReceived += new DataReceivedEventHandler(DataReceived);
            return p;
        }

        /// <summary>
        /// Event handler
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        public void DataReceived(object sender, DataReceivedEventArgs e)
        {
            rawoutput += e.Data;
            output += e.Data + Environment.NewLine;
        }

        protected override void OnExecutePrepare(ProcessRunnerArguments e)
        {
            this.process = createProcess(e);
        }

        protected override ProcessRunnerData OnExecute(ProcessRunnerArguments e)
        {
            this.process.Start();
            this.process.BeginOutputReadLine();
            this.process.BeginErrorReadLine();
            this.process.WaitForExit();
            exitcode = this.process.ExitCode;
            //Return the data
            return new ProcessRunnerData()
                {
                    Message = string.Format(getString("SVN0106"), e.Command),
                    ExitCode = exitcode,
                    Command = e.Command,
                    Options = e.Options,
                    Output = output,
                    RawOutput = rawoutput
                };
        }

        protected override void OnExecuteFail(Exception e)
        {
            //Let the abstract class handle it
        }

        protected override void OnExecuteFinalize()
        {
            //Dispose the process
            this.process.Close();
            this.process.Dispose();
        }

        #endregion
    }
}
